package cn.ticsmyc.tools.multiThread.twoPhaseTermination;

import java.lang.ref.WeakReference;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 记录是否需要停止线程的线程停止标志
 *
 * @author Ticsmyc
 * @date 2021-06-01 16:36
 */
public class TerminationToken {

    /**
     * 使用protected修饰，只给子类看
     * 使用volatile修饰，保证可见性
     */
    protected volatile boolean toShutDown = false;

    /**
     * 记录当前线程还有多少任务要做， 小于等于0时表示可以直接停止
     */
    public final AtomicInteger reservations = new AtomicInteger(0);

    /**
     * 记录使用这个token的所有线程
     * 使用WeakReference，不影响已经停止的线程的垃圾回收
     */
    private final Queue<WeakReference<Terminatable>> coordinatedThreads;

    public TerminationToken() {
        this.coordinatedThreads = new ConcurrentLinkedDeque<>();
    }

    public boolean isToShutDown() {
        return toShutDown;
    }

    public void setToShutDown(boolean toShutDown) {
        this.toShutDown = toShutDown;
    }

    /**
     * 注册一个使用了这个token的线程
     *
     * @param thread
     */
    protected void register(Terminatable thread) {
        this.coordinatedThreads.add(new WeakReference<>(thread));
    }

    /**
     * 因为使用这个token的某个线程终止， 需要通知其他线程也终止。
     *
     * @param thread
     */
    protected void notifyThreadTermination(Terminatable thread) {
        WeakReference<Terminatable> weakReference;
        while ((weakReference = this.coordinatedThreads.poll()) != null) {
            Terminatable otherThread = weakReference.get();
            if(otherThread != null && !otherThread.equals(thread)) {
                otherThread.terminate();
            }
        }
    }
}
